前言
相信点开文章的你,多少也知道或者使用过Retrofit框架吧。如果你有一颗想对源码一探究竟的心,却不知如何入手。笔者一直也有这样的困惑,也正在努力总结出一套有效的分析源码方法,希望本文的拆轮子思路能给你带来一些帮助。
本文记录了笔者基于 Retrofit 2.1.0 源码的学习分析过程,文中拆解思路很大程度受到Stay4it所制作的教程启发(良心教程,文末有链接,配合视频食用本文效果更佳),故跟随该教程结合自身见解进行一番记录,如有错漏,恳请指正。
探索方式:
- 学会用该框架,动手写Demo,理解框架应用场景,基本特点(前提)。
- 利用网络资源,搜寻多篇前人写过的拆轮子资源,下载源码,跟随资源进行源码跟踪,如果不动手,我认为是很难将框架理解的。
- 阅读源码时,学会总结:从Retrofit一般使用方式入手,通过断点调试,观察源码执行顺序,忽略非重要代码,摸清源码主线实现思路后,再深入探索其中的细节实现。
- 回顾与整理,最后再过一遍思路,若走通了,那么框架的大概就理解了,同时整理笔记,便于日后忘了回来查看。
网络请求框架的基本流程
- 构建Request,入队
- 进入Executor执行,Looper不断循环,拿到Request执行
- 执行结果的解析与返回
Retrofit 概述(WHAT)
一个在Android/Java平台上运行的type-safe HTTP Client,其中type-safe是通过声明泛型来保证的,支持RxJava,解耦程度高,基于 Retrofit 2.0.1,当前最新版2.1.0,即将出版2.2.0。(2017.1.)
构建Request
Retrofit通过注解来构建Request,所有的参数都可以简单配置完毕,上层不需要关心底层使用何种方式实现构建Request过程。
实现Executor
实现上述声明的接口,得到可以做具体请求操作的实现类。
相关概念
CallAdapter:Adapter a Call into the type of T.(将一个Call适配为另外一个Call的适配器接口)
- Type responseType():将返回的请求转化为参数Type类型
- T adapt(Call
call):将一个Call转换成另外一个Call
HTTP Call
调用上述实现类的方法即可得到Call,而Retrofit内部使用OkHttp实现HTTP Call,最后通过Converter转换成用户想要的对象体。
Call:An invocation of a Retrofit method that sends a request to a webserver and returns a response.(请求发送与响应返回方法的调用)
主线用例
|
|
Retrofit主线源码剖析(HOW - Part 1)
Retrofit对象的创建
1234Retrofit retrofit = new Retrofit.Builder().baseUrl("http://gank.io/").addConverterFactory(GsonConverterFactory.create()).build();build()方法内部
构建Retrofit对象主要思路:1、创建callbackExecutor(内部获取主线程MainLooper来构建Hanlder,其execute方法本质是Handler.post(runnable),待用于线程切换);2、构建adapterFactories集合,将defaultAdapterFactory加入其中(ExecutorCallAdapterFactory类,线程切换关键实现,内部持有OkHttp代理delegate,在delegate.enqueue中的onRespond方法内使用刚刚创建的callbackExecutor.execute方法,从而实现线程切换)1234567891011121314151617181920212223242526272829public Retrofit build() {...// 创建OkHttp,目前Retrofit只支持OkHttpokhttp3.Call.Factory callFactory = this.callFactory;if (callFactory == null) {callFactory = new OkHttpClient();}// 创建Executor,见步骤3Executor callbackExecutor = this.callbackExecutor;if (callbackExecutor == null) {callbackExecutor = platform.defaultCallbackExecutor();}// Make a defensive copy of the adapters and add the default Call adapter.// 对adapters进行保护性拷贝,并且加入默认的call adapter(使用上面创建的Executor来构建,可以认为是把主线程中的Handler传入)// 构建adapterFactories集合,将defaultAdapterFactory加入其中,见步骤4List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));// Make a defensive copy of the converters.// 对converters进行保护性拷贝// 一般传入的为GsonConverterFactory对象,其作用主要是将json转换成java对象List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);//最终完成Retrofit对象构建return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,callbackExecutor, validateEagerly);}Executor的获取 - platform.defaultCallbackExecutor();
1234567891011121314151617181920212223static class Android extends Platform {public Executor defaultCallbackExecutor() {// 返回MainThreadExecutorreturn new Platform.Android.MainThreadExecutor();}CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {return new ExecutorCallAdapterFactory(callbackExecutor);}static class MainThreadExecutor implements Executor {// 从主线程得到MainLooper,构建Handlerprivate final Handler handler = new Handler(Looper.getMainLooper());public void execute(Runnable r) {// execute方法本质:通过handler,在主线程上执行该runnablehandler.post(r);}}}详解 platform.defaultCallAdapterFactory(callbackExecutor) - 线程切换的关键
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465// platform.defaultCallAdapterFactory(callbackExecutor)CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {if (callbackExecutor != null) {return new ExecutorCallAdapterFactory(callbackExecutor);}return DefaultCallAdapterFactory.INSTANCE;}// ExecutorCallAdapterFactory构造方法// ExecutorCallAdapterFactory通过传参,得到callbackExecutorExecutorCallAdapterFactory(Executor callbackExecutor) {this.callbackExecutor = callbackExecutor;}// get方法,创建并返回Android平台默认CallAdapterpublic CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {if (getRawType(returnType) != Call.class) {return null;}final Type responseType = Utils.getCallResponseType(returnType);return new CallAdapter<Object, Call<?>>() {public Type responseType() {return responseType;}public Call<Object> adapt(Call<Object> call) {return new ExecutorCallbackCall<>(callbackExecutor, call);}};}//----------------------------分割线-----------------------------------// ExecutorCallAdapterFactory内部类ExecutorCallbackCall中enqueue方法,子线程转换为主线程的关键public void enqueue(final Callback<T> callback) {if (callback == null) throw new NullPointerException("callback == null");// 子线程中执行,此处的delegate本质是OkHttpCall(主要用于对接OkHttp框架)delegate.enqueue(new Callback<T>() {public void onResponse(final Call<T> call, final Response<T> response) {// 响应请求,调用callbackExecutor的execute// 从步骤3中可知,该方法本质是调用主线程的Handler执行runnable// 包裹用户传入的callback,从而实现线程切换callbackExecutor.execute(new Runnable() {public void run() {if (delegate.isCanceled()) {// Emulate OkHttp's behavior of throwing/delivering an IOException oncancellation.callback.onFailure(call, new IOException("Canceled"));} else {callback.onResponse(call, response);}}});}public void onFailure(final Call<T> call, final Throwable t) {// 包裹用户传入的callback,从而实现线程切换callbackExecutor.execute(new Runnable() {public void run() {callback.onFailure(call, t);}});}});}详解:retrofit.create(Api.class)
创建接口实现类:创建并返回一个会拦截接口方法的动态代理对象实例 - 接口方法被调用时,会被其拦截,内部将接口方法适配成HTTP Call,再构造对应的OkHttpCall,最后通过CallAdapter.adapt()转换成Retrofit适用的call delegates(即ExecutorCallbackCall)。12345678910111213141516171819202122Api api = retrofit.create(Api.class);// create方法内部实现,返回一个动态代理实例public <T> T create(final Class<T> service) {...// 该动态代理会对接口方法进行拦截return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },// 创建一个InvocationHandler,接口方法被调用时会被拦截调用new InvocationHandler() {private final Platform platform = Platform.get();// 当Api接口方法被调用时,会调用invoke方法拦截public Object invoke(Object proxy, Method method, Object... args)throws Throwable {...// 通过解析api方法注解、传参,将接口中方法适配成HTTP Call,详解见步骤6ServiceMethod serviceMethod = loadServiceMethod(method);// 拦截下来之后,内部构建一个okHttpCallOkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);// 最后通过callAdapter将okHttpCall转换成为Retrofit适用的call delegates(代理),Android平台默认使用ExecutorCallAdapterFactory,adapt返回ExecutorCallbackCall(即步骤4)return serviceMethod.callAdapter.adapt(okHttpCall);}});}详解 ServiceMethod serviceMethod = loadServiceMethod(method);
ServiceMethod整体思路: 内部主要是将方法中的注解取出,转换成HTTP Call的逻辑,暂且不深究。
下面看loadServiceMethod方法的实现123456789101112131415// 内部有缓存以提高性能,避免重复解析 - 使用LinkedHashMap来存储ServiceMethod,与接口中方法一一对应private final Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>();ServiceMethod loadServiceMethod(Method method) {ServiceMethod result;synchronized (serviceMethodCache) {// 通过传入的方法,从Map中取出对应的ServiceMethodresult = serviceMethodCache.get(method);if (result == null) {// 如果还没有实现,则构造一个ServiceMethod实例放入Map中result = new ServiceMethod.Builder(this, method).build();serviceMethodCache.put(method, result);}}return result;}回到主线,retrofit.create()方法创建好实现类后,调用接口方法获得Call,前面步骤5已经说道,当接口方法被调用时候,会被拦截并且转换成HTTP Call。
下面我们使用call进行enqueue操作:此处的call,即ExecutorCallbackCall,它有execute(同步)、enqueue(异步)两个方法,其中enqueue方法,可达到子线程请求,成功后切换回主线程的效果(原理 - 步骤4),免去了开启线程、使用handler跨线程通信的操作。12345678910111213Call<BaseModel<ArrayList<Benefit>>> call = api.defaultBenefits(20, page++);call.enqueue(new Callback<BaseModel<ArrayList<Benefit>>>() {// 该处的onResponse方法已经转换到主线程上了,而转换关键在于Retrofit对象构建时,defaultAdapterFactory内部实现,见步骤2->步骤4public void onResponse(Call<BaseModel<ArrayList<Benefit>>> call, Response<BaseModel<ArrayList<Benefit>>> response) {...}public void onFailure(Call<BaseModel<ArrayList<Benefit>>> call, Throwable t) {...}}Retrofit主线流程总结:
1. Retrofit对象的构建 - Retrofit.Builder()…build():①构建OkHttpClient,目前Retrofit仅支持OkHttpClient;②构建Executor:优先根据用户提供的callBackExcecutor来构建,若用户没有提供,则提供defaultCallbackExecutor(其内部会获取MainLooper构建handler,execute方法直接handler.post(runnable),实现在主线程上的操作);③使用executor来构建adapterFactories集合,优先将用户提供的adapterFactory加入到其中,再加上defaultCallAdapterFactory(传入②创建的callbackExecutor,defaultCallAdapterFactory内部持有OkHttpCall,在其enqueue方法中的onResponse方法调用defaultCallbackExecutor.execute方法,从而实现线程切换操作);④最终使用Retrofit构造方法构建Retrofit实例对象2. Retrofit接口方法的实现方式 - retrofit.create(接口名.class):①create方法创建并返回动态代理对象实例,动态代理对象内部会拦截接口方法的调用②动态代理内部通过ServiceMethod将接口方法适配成HTTP Call,再构造对应的OkHttpCall,最后通过CallAdapter转换成Retrofit适用的call delegate(ExecutorCallbackCall)。
3. 使用动态代理(接口实现类)调用接口方法得到Call、使用call.enqueue进行异步请求:①调用接口方法时,动态代理对象(接口实现类)内部拦截;②调用call.enqueue,内部会调用ExecutorCallAdapter的enqueue方法,enqueue中onResponse方法调用defaultCallbackExecutor.execute方法,使用主线程Handler.post(runnable)从而实现线程切换操作。
- Retrofit主线流程总结图解(从上往下阅读):
Retrofit源码深入探索(HOW - Part 2)
retrofit.create()方法中一段令人疑惑的代码,却是Retrofit工作主要代码:
123456// ①创建ServiceMethod,见深入探索步骤2ServiceMethod<Object, Object> serviceMethod = (ServiceMethod<Object, Object>) loadServiceMethod(method);// ②传入ServiceMethod构造OkHttpCall,使用构造方法传入成员变量OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);// ③又将构造好的OkHttpCall传回,通过ServiceMethod中的callAdapter来进行转换,见步骤4return serviceMethod.callAdapter.adapt(okHttpCall);解析ServiceMethod:Adapts an invocation of an interface method into an HTTP call - 将接口中的方法适配成HTTP Call
loadServiceMethod内部通过Builder,build()方法创建:内部创建了CallAdapter(例:defaultCallAdapterFactory - 将Http Call 转成Retrofit中的Call->调用okHttp3.Call->线程切换)、Converter(请求结果转换器,例:Gson)、callFactory(okhttp3.Call.Factory - 对接okHttp)、12345678910111213141516171819202122232425public ServiceMethod build() {// callAdapter的创建callAdapter = createCallAdapter();//追踪代码可知:本质通过retrofit.nextCallAdapter方法创建,见步骤3responseType = callAdapter.responseType();...// 创建ResponseConverter(转换器 - 对象与Http表示形式相互转换)responseConverter = createResponseConverter();// 解析注解参数,逻辑不必深究for (Annotation annotation : methodAnnotations) {parseMethodAnnotation(annotation);}...return new ServiceMethod<>(this);}// 构造方法,内部参数基本都由Retrofit提供ServiceMethod(Builder<R, T> builder) {// 负责创建HTTP请求,一个可以执行的HTTP请求(okHttp3.Call),仅支持OkHttpClientthis.callFactory = builder.retrofit.callFactory();// 将Retrofit中的Call<T>转为T(Retrofit中的Call ≠ okHttp中的Call,前者表示retrofit接口方法调用,内部通过后者实现,最后通过)this.callAdapter = builder.callAdapter;// 将响应类型适配成用户指定的类this.responseConverter = builder.responseConverter;// 对象与Http表示形式相互转换的转换器this.parameterHandlers = builder.parameterHandlers;// 解析接口注解参数...// 略去非重点关注成员变量}CallAdapter的创建:遍历adapterFactories,找到并返回合适的adapter
123456789101112131415161718192021222324public CallAdapter<?, ?> nextCallAdapter(CallAdapter.Factory skipPast, Type returnType,Annotation[] annotations) {...// 遍历adapterFactories,找到可以接收指定类型的adapterfor (int i = start, count = adapterFactories.size(); i < count; i++) {// 通过get方法,获得相匹配的类型CallAdapter<?, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this);if (adapter != null) {// 找到合适adapter,返回return adapter;}}...}//下面看看一般的adapterFactories源码//1、ExecutorCallAdapterFactory中的get方法public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {// 如果返回类型为Call类型,则使用它if (getRawType(returnType) != Call.class) {return null;}...}//2、RxJavaCallAdapterFactory、RxJavaCallAdapterFactory中的get方法是Observable类型(源码略显复杂掠过)解析serviceMethod.callAdapter.adapt方法:因callAdapter类型而异,ExecutorCallAdapterFactory适配的是ExecutorCallbackCall类型,而RxJava适配的是Observable类型
注意:无论是什么类型的callAdapter,最终都会调用OkHttpCall中的enqueue、execute方法,把实际的工作交给OkHttp来做,详见步骤5123456789101112131415// ExecutorCallAdapterFactorypublic Call<Object> adapt(Call<Object> call) {return new ExecutorCallbackCall<>(callbackExecutor, call);}// RxJavaCallAdapterpublic Object adapt(Call<R> call) {OnSubscribe<Response<R>> callFunc = new CallOnSubscribe<>(call);OnSubscribe<?> func;// 构造订阅者func逻辑,省略...// 通过func构造ObservableObservable<?> observable = Observable.create(func);// Observable配置逻辑,省略...return observable;}解析OkHttpCall调用链:OkHttp的包装类,与OkHttp对接,实现了Retrofit中的Call接口,内部使用OkHttp框架来进行实际操作,解析好数据后再调用传入的callbackA -(内部通过Execute实现线程切换)->调用用户传入的callbackInMainThread(漫长的一个调用链..)
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748// 从上面分析可知,调用接口定义方法返回ExecutorCallbackCall// call.enqueue(callbackInMainThread); 调用其enqueue方法,内部持有OkHttpCall 作为 delegate// 将callbackInMainThread包裹executor实现线程切换,生成callbackA// delegate.enqueue(callbackA); 上面的方法内部会调用delegate.enqueue方法以对接OkHttp框架// 下面看OkHttpCall的enqueue方法(OkHttp框架里的方法,与Retrofit无关)public void enqueue(final Callback<T> callback) {...okhttp3.Call call;...call.enqueue(new okhttp3.Callback() {public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)throws IOException {Response<T> response;try {// onResponse时候进行数据转换,关键点:Converter (下方附有调用链)response = parseResponse(rawResponse);} catch (Throwable e) {callFailure(e);return;}callSuccess(response);}...// 请求失败调用callbackA.onFailure -(内部线程切换)-> callbackInMainThread.onFailureprivate void callFailure(Throwable e) {try {callback.onFailure(OkHttpCall.this, e);} catch (Throwable t) {t.printStackTrace();}}// 响应成功调用callbackA.onResponse -(内部线程切换)-> callbackInMainThread.onSuccess或onFailureprivate void callSuccess(Response<T> response) {try {callback.onResponse(OkHttpCall.this, response);} catch (Throwable t) {t.printStackTrace();}}});}// 数据转换调用链:parseResponse -(关键调用)-> serviceMethod.toResponse -> GsonRequestBodyConverter.convertResponse<T> parseResponse(okhttp3.Response rawResponse) throws IOException {...T body = serviceMethod.toResponse(catchingBody);...}
Retrofit中的设计模式,解耦方式(WHY)
Retrofit中涉及不少的设计模式,笔者能力有限,设计模式方面知识储备不足,仍需继续努力,这里暂且给出设计模式定义与链接,作初步认识。
门面模式(Facade Pattern)
Retrofit - retrofit.create()
定义:外部与一个子系统的通信必须通过一个统一的外观对象进行,为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。门面模式又称为外观模式,它是一种对象结构型模式。
传送门:xingjiarong - 门面模式
工厂模式
Retrofit中的三大工厂 - okhttp3.Call.Factory,CallAdapter.Factory 和 Converter.Factory
定义:又称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式(同属于创建型模式的还有工厂方法模式,抽象工厂模式,单例模式,建造者模式)。在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
传送门:xingjiarong - 简单工厂模式、xingjiarong - 抽象工厂模式
装饰模式
ExecutorCallbackCall类:在源“OkHttpCall”操作时,进行线程切换操作
定义:动态地给一个对象增加一些额外的职责(Responsibility),就增加对象功能来说,装饰模式比生成子类实现更为灵活。其别名也可以称为包装器(Wrapper),与适配器模式的别名相同,但它们适用于不同的场合。根据翻译的不同,装饰模式也有人称之为“油漆工模式”,它是一种对象结构型模式。
传送门:design-patterns - 装饰模式
动态代理
ExecutorCallbackCall中的delegate的动态设置,从而针对不同代理采用不同方法
定义:给某个对象提供一个代理对象,并由代理对象控制对于原对象的访问,即客户不直接操控原对象,而是通过代理对象间接地操控原对象。
传送门:xiazdong - 代理模式及Java实现动态代理
适配器模式
CallAdapter,各种适配器,将一个东西适配成一个适合我们使用的东西
定义:适配器模式将一个类的接口,转化成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间。
传送门:xingjiarong - 适配器模式
策略模式
CallAdapter内部还夹杂着策略模式?
定义:定义一系列算法,将每一个算法封装起来,并让它们可以相互替换。策略模式让算法独立于使用它的客户而变化,也称为政策模式(Policy)。
传送门:xingjiarong - 策略模式、design-patterns - 策略模式
Stay的详细分析:Retrofit分析-经典设计模式案例